<?php
/**
 * PrynLib
 * @copyright 2007-2009 Prynel
 * @author Olivier ROGER <roger.olivier@gmail.com>
 * @category libPrynel
 * @package Auth
 * @version $Revision: 102 $
 */

/**
 * Identification d'utilisateur via BDD
 * @category libPrynel
 * @package Auth
 * @version 1.2.0 
 * @author Olivier ROGER <roger.olivier@gmail.com>
 * @copyright  2007-2009 Prynel
 * @todo Gérer les redirections      
 * <code>
 * // Exemple d'identification
 * $sess = Session_Session::getInstance('nomSession',10);
 * $auth = new Auth($sess);
 * $auth->userTable = 'user';
 * $auth->userField = 'login';
 * $auth->pwdField  = 'pwd';
 * $auth->pwdHash   = 'sha256';
 * $auth->timeOutSession = 120;
 * $auth->login($_POST['login'],$_POST['mdp']);
 * if(!$auth->error)
 * {
 *   if($auth->isLogged())
 *   {
 *     echo 'Connnecté';
 *     print_r($_SESSION);
 *   }
 *   else
 *     echo 'pas Connecté';
 *   }
 * else
 * {
 *   echo $auth->displayError();
 * }
 * </code>
 */

class Auth_Auth
{
	const NO_ERROR    = 0;
	const ERROR_LOG   = 1;
	const ERROR_PASS  = 2;
	const ERROR_TABLE = 3;
	const ERROR_FIELD = 4;

	/**
	 * Objet pour accès bdd
	 * @access private
	 * @var Db_Spdo
	 */
	private $oDB;
	
	/**
	 * Type d'erreur rencontrée
	 * @access private
	 * @var int $errorType
	 */
	private $errorType;
	
	/**
	 * Message d'erreur
	 * @access private
	 * @var string $errorMsg
	 */
	private $errorMsg;
	
	/**
	 * Table des utilisateurs
	 * @access public
	 * @var string $userTable
	 */
	public $userTable;
	
	/**
	 * Champs du nom d'utilisateur
	 * @access public
	 * @var string $userField
	 */
	public $userField;
	
	/**
	 * Champs du mot de passe
	 * @access public
	 * @var string $pwdField
	 */
	public $pwdField;
	
	/**
	 * Type de hash pour le mdp (md5,sha...). Par défaut md5
	 * 
	 * @var string $pwdHash
	 */
	public $pwdHash;
	/**
	 * Connexion automatique
	 * @access public
	 * @var boolean $autoLogin
	 */
	public $autoLogin;
	
	/**
	 * Option des cookies
	 * @access public
	 * @var array $cookieOption
	 */
	public $cookieOption;
	
	/**
	 * Temps d'expiration de session en seconde
	 * @access public
	 * @var int $timeOutSession
	 */
	public $timeOutSession;
	
	/**
	 * Page de redirection en cas d'erreur
	 * @access public
	 * @var string $redirectError
	 */
	public $redirectError;
	
	/**
	 * Redirection en cas de succès
	 * @access public
	 * @var string $redirect
	 */
	public $redirect;
	
	/**
	 * Erreur lors de l'identification
	 *
	 * @var boolean $error
	 */
	public $error;
	
	/**
	 * Session
	 *
	 * @var Session_Session
	 */
	private $session;
	
	/**
	 * Constructeur
	 *
	 * @param Db_mysql $objetBdd
	 * @param Session_Session $session
	 * @access public
	 */
	public function __construct($session)
	{
		$this->oDB            = Db_Spdo::getInstance();
		$this->userTable      = 'user';
		
		$this->userField      = 'login';
		$this->pwdField       = 'password';
		$this->pwdHash        = 'md5';
		$this->autoLogin      = false;
		$timeTTL              = time()+(365*24*3600);
		$this->cookieOption   = array('name'=>'loginCookie',
									  'ttl'=>$timeTTL,
									  'path'=>'/',
									  'domain'=>null,
									  'token'=>'Phrase de token pour saler mdp');
		$this->timeOutSession = 0;
		$this->redirectError  = 'index.php';
		$this->redirect       = (!empty($_SERVER['HTTP_REFERER']))?$_SERVER['HTTP_REFERER']:'';
		$this->error          = false;
		$this->errorType      = self::NO_ERROR;
		$this->errorMsg       = '';
		
		$this->session		  = $session;
		if(!isset($session->AC_lastAct))
		{
			$session->AC_connected 		= 0;
			$session->AC_lastAct 		= 0;
		}
	}
	
	/**
	 * Identification classique via formulaire
	 *
	 * @param string $login
	 * @param string $pass
	 */
	public function login($login,$pass)
	{
		if($this->checkUser($login))
			if($this->checkPass($login,$pass))
			{
				$this->startSession();
				$this->session->AC_connected 	= true;
				$this->session->AC_lastAct		= time();
				if($this->autoLogin)
				{
					$pass = $this->hashPass($pass);
					$this->createCookie($login,$pass);
				}
			}
			else
				$this->displayError();
		else
			$this->displayError();
	}
	
	public function logout()
	{
		$this->destroySession();
		$this->destroyCookie();
	}
	
	/**
	 * Vérifie si l'utilisateur est identifié
	 *
	 * @return boolean
	 */
	public function isLogged()
	{
		$lastActivity = time()-$this->session->AC_lastAct;
		// Cas 1 - Session existante illimité
		if($this->session->AC_connected === true && $this->timeOutSession==0)
		{
			$this->session->AC_lastAct = time();
			if($lastActivity>300)
				$this->session->refresh();
			return true;
		}
		// Cas 2 - Session limité mais existante et TTL non dépassé
		elseif($this->session->AC_connected === true && $lastActivity < $this->timeOutSession && $this->timeOutSession!=0)
		{
			$this->session->AC_lastAct = time();
			if($lastActivity>300)
				$this->session->refresh();
			return true;
		}
		// Cas 3 - Session limité mais existante et TTL dépassé
		elseif($this->session->AC_connected === true && $lastActivity > $this->timeOutSession && $this->timeOutSession!=0)
		{
			$this->logout();
			return false;
		}
		// Cas 4 - Session inexistante mais autologin
		elseif(!isset($this->session->AC_connected) && $this->autoLogin)
		{
			if($this->loginCookie())
				return true;
			else
				return false;
		}
		// Tout autre cas
		else
		{
			return false;
		}
	}
	
	/**
	 * Affichage des erreurs
	 *
	 * @return string
	 */
	public function displayError()
	{
		switch($this->errorType)
		{
			case self::ERROR_LOG:
				$this->errorMsg = 'Identifiant incorrect';
				break;
			case self::ERROR_PASS:
				$this->errorMsg = 'Mot de passe incorrect';
				break;
		}
		return $this->errorMsg;
	}
	
	/**
	 * Identification via cookie
	 *
	 * @return boolean
	 */
	private function loginCookie()
	{
		if(isset($_COOKIE[''.$this->cookieOption['name'].'']))
		{
			$tabUser 	= unserialize($_COOKIE[''.$this->cookieOption['name'].'']);
			$logCookie 	= $tabUser[0];
			$passCookie = $tabUser[1];
			if($this->checkUser($tabUser[0]))
			{
				$prepare 	= $this->oDB->prepare('SELECT '.$this->pwdField.' FROM '.$this->userTable.' WHERE '.$this->userField.' = :logCookie');
				$prepare->execute(array(':logCookie'=>$logCookie));
				$data 		= $prepare->fetch(); 
				$passBdd    = md5($this->cookieOption['token'].$data[0]);
				if($passCookie == $passBdd)
				{
					$this->startSession();
					$this->session->AC_connected	= true;
					$this->session->AC_lastAct  	= time();
					$this->createCookie($logCookie,$passCookie);
					return true;
				}
				else
				{
					$this->error 		= true;
					$this->errorType 	= self::ERROR_PASS;
					$this->displayError();
				}
			}
			else
				$this->displayError();
		}
		return false;
	}
	
	/**
	 * Démarrage session si innexistante
	 *
	 */
	public function startSession($name='acauth')
	{
		if(empty($this->session))
			$this->session = Session_Session::getInstance($name,$this->timeOutSession);
	}
	
	/**
	 * Création du cookie avec salage du mdp avec le token
	 *
	 * @param string $login
	 * @param string $pass mdp hasher
	 */
	private function createCookie($login,$pass)
	{
		$login = htmlspecialchars($login,ENT_QUOTES);
		$pass  = htmlspecialchars($pass,ENT_QUOTES);
		$value = serialize(array($login,md5($this->cookieOption['token'].$pass)));
		setcookie($this->cookieOption['name'],$value,$this->cookieOption['ttl'],$this->cookieOption['path'],$this->cookieOption['domain']);
		//echo $_COOKIE['loginCookie'];
	}
	
	/**
	 * Destruction de la session et de toute les variables associées
	 *
	 */
	private function destroySession()
	{
		$this->session->destroy();
	}
	
	/**
	 * Destruction du cookie
	 *
	 */
	private function destroyCookie()
	{
		setcookie($this->cookieOption['name'],NULL,time()-1,$this->cookieOption['path'],$this->cookieOption['domain']);
	}
	/**
	 * Vérification de l'identifiant
	 *
	 * @param string $user
	 * @return boolean
	 */
	private function checkUser($user)
	{
		$prepare = $this->oDB->prepare('SELECT '.$this->userField.' FROM '.$this->userTable.' WHERE '.$this->userField.' = :user');
		$prepare->execute(array(':user'=>$user));
		if($prepare->fetchColumn())
			return true;
		else
		{
			$this->error     = true;
			$this->errorType = self::ERROR_LOG;
			return false;
		}
	}
	
	/**
	 * Vérification du mot de passe
	 *
	 * @param string $login Identifiant
	 * @param string $pass
	 * @access private
	 * @return boolean
	 */
	private function checkPass($login,$pass)
	{
		$pass = $this->hashPass($pass);
		$prepare = $this->oDB->prepare('SELECT '.$this->pwdField.' FROM '.$this->userTable.' WHERE '.$this->pwdField.'=:pass AND '.$this->userField.' = :login');
		$prepare->execute(array(':pass'=>$pass,':login'=>$login));
		if($prepare->fetchColumn())
			return true;
		else
		{
			$this->error     = true;
			$this->errorType = self::ERROR_PASS;
			return false;
		}
	}
	
	/**
	 * Hash le mot de pass dans l'algo souhaité
	 *
	 * @param string $algo
	 * @param string $pass
	 * @return string
	 */
	private function hashPass($pass)
	{
		if($this->pwdHash!='nohash')
			return hash($this->pwdHash,$pass);
		else
			return $pass;
	}
	
	/**
	 * Retourne l'erreur si existante
	 *
	 * @since 1.0.5
	 * @return int
	 */
	public function getErrorType()
	{
		return $this->errorType;
	}
	
}
 ?>